package com.gj.xxl.job.admin.core.route.strategy;

import com.gj.xxl.job.admin.core.route.RouteStrategy;

import java.util.List;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 轮询路由策略
 */
public class RoundRouteStrategy implements RouteStrategy {

    //key 是 jobId，value 是任务对应的序号
    private static ConcurrentHashMap<Integer, AtomicInteger> routeSequenceMap = new ConcurrentHashMap<>();

    private static Random random = new Random();

    //Map 中数据的过期时间
    private static long expireTime = 0;

    @Override
    public String route(Integer jobId, List<String> addressList) {
        if (System.currentTimeMillis() > expireTime) {
            routeSequenceMap.clear();

            expireTime = System.currentTimeMillis() + 1000 * 60 * 60 * 24;
        }

        AtomicInteger sequence = routeSequenceMap.get(jobId);
        if (sequence == null || sequence.get() > 100_0000) {
            //sequence 初始化的逻辑还是挺有意思的，为什么不直接设置成 0 呢？
            //这是因为如果每一个定时任务第一次执行的时候，如果不弄一个随机数做取模运算，
            //那么定时任务都会路由到一个执行器上，
            //假如这个时候有很多的定时任务第一时间执行，都会路由到同一个执行器上，
            //可能会给这一台机器过大的压力。
            //执行器搭建了集群，为的就是负载均衡，分散压力，所以这里弄一个随机数，把第一次执行定时任务的压力分散到各个执行器上
            sequence = new AtomicInteger(random.nextInt(100));
            routeSequenceMap.put(jobId, sequence);
        } else {
            sequence.addAndGet(1);
        }

        return addressList.get(sequence.get() % addressList.size());
    }
}
